package com.zhiwang.planet.mvp.p

import android.annotation.SuppressLint
import android.os.Environment
import android.text.TextUtils
import android.util.Log
import com.tencent.bugly.crashreport.BuglyLog
import com.tencent.bugly.crashreport.CrashReport
import com.uber.autodispose.AutoDispose.autoDisposable
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
import com.zhiwang.planet.aop.net.NetWorkRequired
import com.zhiwang.planet.di.ActivityScope
import com.zhiwang.planet.mvp.v.*
import com.zhiwang.planet.mvvm.model.ResponseFunc
import com.zhiwang.planet.mvvm.model.RestApi
import com.zhiwang.planet.mvvm.model.entity.ShareInformation
import com.zhiwang.planet.mvvm.model.entity.User
import com.zhiwang.planet.mvvm.model.entity.UserDao
import com.zhiwang.planet.mvvm.model.entity.main.*
import com.zhiwang.planet.mvvm.model.request.*
import com.zhiwang.planet.util.*
import io.reactivex.Observable
import io.reactivex.ObservableSource
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.BiFunction
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import okhttp3.MediaType
import okhttp3.RequestBody
import java.io.File
import javax.inject.Inject


@ActivityScope
class UserPresenter @Inject constructor(var restApi: RestApi, var userDao: UserDao, var scopeProvider: AndroidLifecycleScopeProvider) {

    lateinit var wxLoginView: WxLoginView
    lateinit var diamondBeanInfoView: DiamondBeanInfoView
    lateinit var avatarView: AvatarView
    lateinit var findPasswordView: FindPasswordView
    lateinit var changePasswordView: ChangePasswordView
    lateinit var smsCodeView: SmsCodeView
    lateinit var userInfoView: UserInfoView
    lateinit var feedbackView: FeedBackView
    lateinit var withdrawRecordView: WithDrawRecordView
    lateinit var consumptionRecordView: DiamondRecordView
    lateinit var changePayPasswordView: ChangePayPasswordView
    lateinit var inviteInfoView: InviteInfoView
    lateinit var withdrawDataView: WithDrawDataView
    lateinit var nickNameView: NickNameView
    lateinit var wxBindCodeInfoView: WxBindCodeInfoView
    lateinit var vipRecordView: VipRecordView
    lateinit var bindWxView: BindWxView
    lateinit var checkBindWxView: CheckBindWxView


    //上传头像
    fun uploadAvatar(f: File) {
        val requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), f)
        restApi.uploadAvatarPic(requestBody)
                .flatMap(ResponseFunc())
                .flatMap { t ->
                    //更新本地 user的头像地址
//                    val user = userDao.getFirstUser()
//                    user.avatar = com.zhiwang.planet.util.Utils.fixAvatarUrlPrefix(t.file_url)
//                    userDao.updateUser(user)
                    Observable.just(t)
                }
                .observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .`as`(autoDisposable(scopeProvider))
                .subscribe({
                    avatarView.onAvatarChange(it.file_url)
                }, {
                    avatarView.onError(it)
                })

    }

    //修改密码
    fun changePassword(phone: String, password: String, smscode: String) {
        val changePwdRequest = ChangePasswordRequest(phone, password, smscode)
        restApi.changePassword(changePwdRequest)
                .androidSchedule()
                .responseVoidFunc()
                .`as`(autoDisposable(scopeProvider))
                .subscribe({

                }, {
                    changePasswordView.onError(it)
                }, {
                    changePasswordView.onPasswordChanged()
                })
    }

    fun findPassword(phone: String, smscode: String, password: String) {
        val changePwdRequest = FindPasswordRequest(phone, password, smscode)
        restApi.findPassword(changePwdRequest)
                .androidSchedule()
                .responseVoidFunc()
                .`as`(autoDisposable(scopeProvider))
                .subscribe({

                }, {
                    changePasswordView.onError(it)
                }, {
                    changePasswordView.onPasswordChanged()
                })
    }

    //查找本地是否有用户信息，以此填充手机号码以及确定是修改密码还是找回密码
    fun queryUserInfo(): Disposable? {
//        return userDao.getUsers()
//                .androidSchedule()
//                .subscribe({
//                    if (it == null || it.isEmpty() || !TokenManager.isLoginValid())
//                        userInfoView.onUserInfoLoad(null)
//                    else userInfoView.onUserInfoLoad(it[0])
//
//                }, {
//                    userInfoView.onError(it)
//                })
        return null

    }

    fun loadUserInfoEx(onSuccess: (IndexData) -> Unit, onError: (Throwable) -> Unit): Disposable? {

        return restApi.getUserInfoEx().androidSchedule()
                .responseFunc()
                .subscribe({
                    onSuccess.invoke(it)

                }, {

                    onError.invoke(it)

                })
    }

    fun sendFeedBack(feedBack: String): Disposable? {
        val feedbackRequest = FeedBackRequest("意见反馈", feedBack, "xxx")
        return restApi.sendFeedBack(feedBackRequest = feedbackRequest)
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    feedbackView.onError(it)
                }, {
                    feedbackView.onFeedBackSend()
                })
    }

    fun getFindPwdSmsCode(randomStr: String, graphCode: String, phone: String) {
        val smsCodeRequest = SmsCodeRequest(phone, graphCode, randomStr)
        smsCodeRequest.setTypeFind()
        var subscribe = restApi.getSmsCode(smsCodeRequest)
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    smsCodeView.onError(it)
                }, {
                    smsCodeView.onSmsSend()
                })
    }

    fun getChangePwdSmsCode(randomStr: String, graphCode: String, phone: String) {
        val smsCodeRequest = SmsCodeRequest(phone, graphCode, randomStr)
        smsCodeRequest.setTypeChange()
        var subscribe = restApi.getSmsCode(smsCodeRequest)
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    smsCodeView.onError(it)
                }, {
                    smsCodeView.onSmsSend()
                })
    }

    fun getPayPasswordSmsCode(randomStr: String, graphCode: String, phone: String) {
        val smsCodeRequest = SmsCodeRequest(phone, graphCode, randomStr)
        smsCodeRequest.setTypeChange()
        var subscribe = restApi.getSmsCode(smsCodeRequest)
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    smsCodeView.onError(it)
                }, {
                    smsCodeView.onSmsSend()
                })
    }

//    fun getWithDrawRecord(pageIndex: Int) {
//
//        var subscribe = restApi.getWithDrawRecord(pageIndex)
//                .androidSchedule()
//                .responseFunc()
//                .subscribe({
//                    withdrawRecordView.onNextPageLoad(it)
//                }, {
//                    withdrawRecordView.onError(it)
//                }, {
//
//                })
//
//    }

//    fun getFirstPageWithDrawRecord() {
//        var subscribe = restApi.getWithDrawRecord(1)
//                .androidSchedule()
//                .responseFunc()
//                .subscribe({
//                    withdrawRecordView.onPageRefresh(it)
//                }, {
//                    withdrawRecordView.onError(it)
//                }, {
//
//                })
//    }

    fun getDiamondRecordList(page: Int) {
        var subscribe = restApi.getDiamondRecord(PageIndexRequest(page))
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    consumptionRecordView.onRecordLoad(it)
                }, {
                    consumptionRecordView.onError(it)
                }, {

                })
    }

    fun getEnergyRecordList(page: Int) {
        var subscribe = restApi.getEnergyRecord(PageIndexRequest(page))
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    consumptionRecordView.onRecordLoad(it)
                }, {
                    consumptionRecordView.onError(it)
                }, {

                })
    }

    fun bindPayPassword(payPassword: String, smsCode: String) {
        var disposable = restApi.changePaypassword(ChangePayPasswordRequest(payPassword, smsCode))
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    changePayPasswordView.onError(it)
                }, {

                    try {
//                        val user = userDao.getFirstUser()
//                        user.bindInfo.hasSetPaypassword = true
//                        userDao.updateUser(user)

                    } catch (e: Exception) {
                        e.printStackTrace()
                    }

                    changePayPasswordView.onPayPwdChanged()
                })
    }

    @NetWorkRequired
    fun getInviteInfo() {
        var disposable = restApi.getUserInviteInfo(NonsenseRequest())
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    inviteInfoView.onInviteInfoLoad(it)
                }, {
                    inviteInfoView.onError(it)
                }, {

                })

    }

    @SuppressLint("LogNotTimber")
    fun uploadDeviceId(deviceId: String) {
//        val userid = userDao.getFirstUser().userId
//        restApi.uploadDeviceId(DeviceIdRequest(deviceId, userid))
//                .androidSchedule()
//                .responseVoidFunc()
//                .`as`(autoDisposable(scopeProvider))
//                .subscribe({
//
//                }, {
//                    Log.e(BuildConfig.APPLICATION_ID, "设备号上传失败 ${it.message}")
//                }, {
//                    Log.i(BuildConfig.APPLICATION_ID, "设备号上传成功 $deviceId")
//                })
    }

    fun dispose() {

    }

    private fun getWithDrawList(type: String): Disposable {
        return restApi.getWithDrawList(type)
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    withdrawDataView.onWithDrawListLoad(it)
                }, {
                    withdrawDataView.onError(it)
                }, {

                })
    }

    fun getWxWithDrawList(): Disposable {
        return getWithDrawList("weixin")
    }

    fun getAlipayWithDrawList(): Disposable {
        return getWithDrawList("alipay")
    }

    fun setNickName(nickName: String) {
        restApi.setNickName(nickName)
                .androidSchedule()
                .responseVoidFunc()
                .`as`(autoDisposable(scopeProvider))
                .subscribe({
                }, {
                    nickNameView.onError(it)
                }, {
//                    val user = userDao.getFirstUser()
//                    user.userName = nickName
//                    userDao.updateUser(user)
//                    nickNameView.onNickNameSet(nickName)
                })
    }

    val TAG = "UserPresenter"
    @NetWorkRequired
    fun saveShareInfo(cacheDir: File) {


        /*正确写法是 在 最后的回调中下载，以免rxjava去掉订阅*/
        restApi.getShareInformation()
                .responseFunc()
                .subscribeOn(Schedulers.io())
                .`as`(autoDisposable(scopeProvider))
                .subscribe({
                    TokenManager.saveShareInfo(it.title, it.summary, it.img, it.url)
                    //下载图片操作延后到用户点击微信分享
                }, {
                    //                    Toasty.message("${it.message}")
                    BuglyLog.e("saveShareInfo", it?.message)
                    CrashReport.postCatchedException(it)
                }, {

                })
    }

    fun getShareInfo(): ShareInformation {
        val shareInformation = TokenManager.getShareInfo()
        val sharePic = File(Environment.getExternalStorageDirectory(), "planetSharePic").absolutePath
        shareInformation.imgLocalPath = sharePic
        return shareInformation
    }


    fun getQrCode() {
        restApi.getQrCode()
    }

    /**
     * 获取绑定微信的 绑定码和公众号信息
     */
    fun getWxBindCodeInfo() {
        restApi.getWxBindCodeInfo(NonsenseRequest())
                .androidSchedule()
                .responseFunc()
                .`as`(autoDisposable(scopeProvider))
                .subscribe({
                    wxBindCodeInfoView.onLoadWxBindCodeInfo(it)
                }, {
                    wxBindCodeInfoView.onError(it)
                })

    }

    fun getVipRecord(page: Int) {
        restApi.getVipRecord(UrlUtil.ji7BaseUrl() + "vip/opening_record", page)
                .androidSchedule()
                .responseFunc()
                .`as`(autoDisposable(scopeProvider))
                .subscribe({
                    vipRecordView.onLoadVipRecord(it)
                }, {
                    vipRecordView.onError(it)
                }, {

                })
    }

    fun getDiamondAndBeanInfo(): Disposable {
        return restApi.getDiamondAndBeanInfo(NonsenseRequest())
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    diamondBeanInfoView.onLoadDaimondBeanInfo(it)
                }, {
                    diamondBeanInfoView.onError(it)
                })
    }


    fun bindPhone(phone: String, sms: String/*, openid: String=""*/) {
        val req = BindPhoneRequest(phone = phone, sms = sms)
        val subscribe = restApi.bindPhone(req)
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({

                }, {
                    bindWxView.onError(it)
                }, {
//                    val user = userDao.getFirstUser()
//                    user.phone = phone
////                    userDao.deleteAll()
//                    userDao.addUser(user)
//                    TokenManager.savePhone(user.phone)
//                    bindWxView.onWxBind()
                })
    }

    fun bindWxOldUser(phone: String, password: String, openid: String, deviceId: String) {
        val req = BindWxRequest(phone = phone, password = password, openid = openid, deviceid = deviceId)
        req.setTypeBinOldUser()
        val subscribe = restApi.bindWxPhone(req)
                .responseFunc()
                .flatMap(Function<TokenBody, ObservableSource<User>> {
                    TokenManager.saveToken(it.token)
                    return@Function restApi.getUserInfo().responseFunc()
                })
                .androidSchedule()
                .subscribe({
//                    it.avatar = com.zhiwang.planet.util.Utils.fixAvatarUrlPrefix(it.avatar)
//                    userDao.deleteAll()
//                    userDao.addUser(user = it)
//                    TokenManager.saveToken(it.token)
//                    TokenManager.saveUserid(it.userId)
//                    TokenManager.savePhone(it.phone)
//                    //每次登陆切换，都设置异常上报的 userid
//                    CrashReport.setUserId(TokenManager.webviewHeaderUserid())
//                    wxLoginView.onLogin(user = it)
                }, {
                    wxLoginView.onError(it)
                }, {

                })
    }

    fun checkWxBind(code: String, deviceId: String) {

        val subscribe = restApi.checkWxBind(code, deviceId)
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    checkBindWxView.onCheckWxBind(it)
                }, {
                    checkBindWxView.onError(it)
                }, {
                    Log.i(TAG, "checkWxBind: ")
                })

    }

    fun getUserInfo() {
        val subscribe = restApi.getUserInfo()
                .androidSchedule()
                .responseFunc()
                .subscribe({
//                    it.avatar = com.zhiwang.planet.util.Utils.fixAvatarUrlPrefix(it.avatar)
//                    userDao.deleteAll()
//                    userDao.addUser(user = it)
//                    TokenManager.saveToken(it.token)
//                    TokenManager.saveUserid(it.userId)
//                    //每次登陆切换，都设置异常上报的 userid
//                    CrashReport.setUserId(TokenManager.webviewHeaderUserid())
////                    TokenManager.saveDevice(deviceId)
//                    wxLoginView.onLogin(user = it)
                }, {

                    wxLoginView.onError(it)
                })
    }

    /**
     * 一键创建新用户
     */
    fun createWxUser(openid: String, deviceId: String, onSuccess: (() -> Unit), onError: ((Throwable) -> Unit)) {

        //直接生成 新用户
        val wxBindReq = BindWxRequest(direct = "1", openid = openid, deviceid = deviceId)
        wxBindReq.setTypeCreateNew()

        val subscribe = restApi.createWxUser(wxBindReq)
                .responseFunc()
                .flatMap {
                    TokenManager.saveToken(it.token)
                    return@flatMap restApi.getUserInfo().responseFunc()
                }
                .androidSchedule()
                .subscribe({
//                    userDao.deleteAll()
//                    userDao.addUser(user = it)
//                    TokenManager.saveToken(it.token)
//                    TokenManager.saveUserid(it.userId)
//                    //小说 userId
//                    YmConfig.setOutUserId(it.userId)
//                    //每次登陆切换，都设置异常上报的 userid
//                    CrashReport.setUserId(it.userId)
//                    onSuccess()
                }, {
                    onError(it)
                }, {

                })

    }

    fun loadTinyGameList(onLoad: ((TinyGameBody) -> Unit), onError: (Throwable) -> Unit) {

        restApi.getTinyGameList()
                .androidSchedule()
                .responseFunc()
                .autoDispose(scopeProvider)
                .subscribe({
                    onLoad(it)
                }, {
                    onError(it)
                }, {

                })

    }


    /**
     * [restoreAndPlay] 如果有账户信息，回调此方法，并且传入小游戏账户
     * [createAndPlay] 没有游戏账户信息
     */
    fun restoreOrCreateAccountAndPlayGame(restoreAndPlay: (String) -> Unit, createAndPlay: () -> Unit, onError: (Throwable) -> Unit): Disposable? {
        return restApi.getTinyGameList()
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    val accountToken = it.accountToken
                    if (TextUtils.isEmpty(accountToken).not()) {
                        restoreAndPlay(accountToken!!)
                        TokenManager.saveMiniGameAccount(accountToken)
                    } else
                        createAndPlay()

                }, {
                    onError(it)
                }, {

                })
    }


    fun postTinyGameLoggedAccountInfo(accountToken: String, onError: (Throwable) -> Unit) {
        restApi.postTinyGameAccountInfo(TinyGameAccountInfo(accountToken))
                .androidSchedule()
                .responseVoidFunc()
                .autoDispose(scopeProvider)
                .subscribe({

                }, {
                    onError(it)
                }, {
                    //onComplete
                    TokenManager.syncMiniGame()
                })
    }

    class TinyZip(var gameReward: TinyGameReward, var token: String)

    @SuppressLint("CheckResult")
    fun postTinyGamePlayTimeAndGetToken(gameId: String, gamePlayedTimeSeconds: Int, token: String, onSuccess: (String?, String?) -> Unit, onNewToken: (String) -> Unit, onError: (Throwable) -> Unit) {
        val req = GamePlayTimeReport(gameId, gamePlayedTimeSeconds, MD5.getMD5(gameId + gamePlayedTimeSeconds + token).toLowerCase())
        Observable.zip(restApi.postGamePlayTime(req).responseFunc(),
                restApi.getMiniGameTempToken().responseFunc(),
                BiFunction<TinyGameReward, String, TinyZip> { t1, t2 ->
                    TinyZip(t1, t2)

                })
                .androidSchedule()
                .subscribe({
                    onSuccess(it.gameReward.diamondRewardNum, it.gameReward.beanRewardNum)
                    onNewToken(it.token)
                }, {
                    onError(it)
                }, {

                })

    }

    //
    fun checkEverInstallOnThisDevice(deviceId: String, onResult: ((Boolean) -> Unit)) {

        restApi.checkDeviceEverInstalled(deviceId)
                .androidSchedule()
                .responseFunc()
                .autoDispose(scopeProvider)
                .subscribe({
                    onResult(it.visible())
                }, {

                }, {

                })


    }

    fun checkVideoTaskCompleted(onCompleted: (() -> Unit), onNotCompleted: (() -> Unit)): Disposable? {
       return  restApi.checkVideoTaskCompleted()
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    if (it.completed == 1)
                        onNotCompleted.invoke()
                    else onCompleted.invoke()

                }, {
                    Toaster.message(it.localizedMessage)
                }, {

                })

    }

    fun getTinyGameToken(onSuccess: (String) -> Unit, onError: (Throwable) -> Unit, playFunc: (() -> Unit)?): Disposable? {
        return restApi.getMiniGameTempToken()
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    onSuccess(it)
                    playFunc?.invoke()
                }, {

                    onError(it)
                }, {

                })
    }

    fun updateDeviceId(imei: String, onSuccess: (String) -> Unit, onError: (Throwable) -> Unit) {

        restApi.updateDeviceId(ImeiBody(imei))
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({
                }, {

                    onError(it)

                }, {
                    onSuccess(imei)

                })
    }

    fun getSbActivity(onSuccess: (Boolean) -> Unit, onError: (Throwable) -> Unit) {
        restApi.getSbActivity()
                .androidSchedule()
                .responseFunc()
                .subscribe({
                    onSuccess.invoke(it)
                }, {

                    onError(it)
                }, {

                })

    }

    fun checkInviteMan(onSuccess: () -> Unit, onError: (Throwable) -> Unit) {

        restApi.checkInviteMan()
                .androidSchedule()
                .responseVoidFunc()
                .subscribe({  }, { onError(it) }, {onSuccess()})

    }

}